package work.utils;

import static java.lang.System.out;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.h819.core.commons.MyLangUtils;
import com.h819.core.utils.MyDateUtils;

/**
 * @ClassName: StandardCodeUtils
 * @Description: TODO(标准号工具类)
 * @author h819
 * @date June 10, 2009 16:15:24 PM
 * @version V0.1
 * 
 */
public class StandardUtils extends StandardBaseUtils {

	private static Logger log = Logger.getLogger(StandardUtils.class);
	private static StandardUtils instance = null;

	/**
	 * 单例模式，禁止实例化
	 */
	private StandardUtils() {
	}

	// public static StandardUtils getInstance() {
	// if (instance == null) {
	// instance = new StandardUtils();
	// }
	// return instance;
	// }

	// ==========================================
	// 发现的特殊的类别代号
	// CSC/G 3206-2005
	// 特殊样式的：
	// SJ 50597/43-1997
	// HDB/CY 001-2000
	// LYJ 128-1992
	// SCFW/B02 027-2003
	// WBH 010-1990 邮电内部管理规定
	// ==========================================

	/**
	 * 从规范的标准号中解析出来标准类别代号，仅适用于国内标准
	 * 
	 * @param standardCode
	 *            待判断的标准号
	 * @param classCode
	 *            标准平台中的标准类别集合
	 * @return
	 */
	public static String getClassCodeFromStandardCode(String standardCode) {

		if (standardCode == null || standardCode.equals(""))
			return null;

		// 仅能分析国内标准
		// 地方标准
		if (isDBStandardCode(standardCode))
			return StringUtils.substringBefore(standardCode, "/");

		// 国标或行标
		if (StringUtils.contains(standardCode, '/'))
			return StringUtils.substringBefore(standardCode, "/");
		else
			return StringUtils.substringBefore(standardCode, blankSpace);

	}

	/**
	 * 从规范的标准号中判断标准的性质:强制性，推荐性，指导性,标准号应该是规范的国内，否则无法判断
	 * 
	 * @param standardCode
	 *            待判断的标准号
	 * @return 返回 "T"、 "Z"、 "Q"，null 为非国内标准
	 */
	public static String getTypeFromStandardCode(String standardCode) {

		// 仅能分析国内标准
		if (!isGNStandardCode(standardCode))
			return null;

		// 因为已经保证是国内标准，故下面的判断可行
		// 如果出现了其他特殊情况，需要完善此方法
		if (StringUtils.contains(standardCode, "/T"))
			return "T";
		else if (StringUtils.contains(standardCode, "/Z"))
			return "Z";
		else
			return "Q";// 此时地方标准包含"/"，国标和行标无标志
	}

	/**
	 * 根据规范的标准号，得到标准性质相反的标准号。强制性得到推荐性，推荐性得到强制性。
	 * 
	 * 如输入为 GB 123-2010，得到 GB/T 123-2010;输入为 GB/T 123-2010，得到 GB 123-2010。
	 * 
	 * 仅能分析国内标准，标准号应该是规范的，否则无法判断。
	 * 
	 * @param standardCode
	 *            待判断的标准号
	 * @return
	 */
	public static String getReverseTypeStandardCode(String standardCode) {

		String type = getTypeFromStandardCode(standardCode);
		String reverseTypeStandardCode = "";

		// 不规范的标准号
		if (type == null)
			return null;

		if (type.equals("Z") || type.equals("T")) {
			if (isDBStandardCode(standardCode))
				reverseTypeStandardCode = standardCode.replace("/Z", "/")
						.replace("/T", "/");
			else
				reverseTypeStandardCode = standardCode.replace("/Z", "")
						.replace("/T", "");
		}

		if (type.equals("Q")) {
			if (isDBStandardCode(standardCode))
				reverseTypeStandardCode = standardCode.replace("/", "/T");
			else
				reverseTypeStandardCode = standardCode
						.replace(blankSpace, "/T"+blankSpace);
		}

		return reverseTypeStandardCode;

	}

	/**
	 * 规范为完整的四位年代号
	 * 
	 * @param yearCode
	 * @return null 为无法规范
	 */
	public static String getFormatYearCode(String yearCode) {

		return MyDateUtils.fillYear2To4(yearCode);

	}

	/**
	 * 判断标准类别代码在平台中是否存在
	 * 
	 * @param classCodeString
	 * @param classCode
	 *            标准平台中的标准类别集合
	 * @return
	 */
	public static boolean isClassCodeInCapitalSTD(String classCodeString,
			List<String> classCode) {
		return classCode.contains(classCodeString);
	}

	/**
	 * 此函数用来判断给定字符串是否是国内标准号,由 isDBcode,isGBcode,isHBcode 合成(按照GB/T 1.1-2000 要求)
	 * 
	 * @param standardCode
	 *            待判断的标准号
	 * @param classCode
	 *            标准平台中的标准类别集合
	 * @return
	 */
	public static boolean isGNStandardCode(String standardCode) {
		return isGBStandardCode(standardCode) || isDBStandardCode(standardCode)
				|| isHBStandardCode(standardCode);
	}

	/**
	 * 此函数用来判断是否是地标 (按照GB/T 1.1-2000 要求)
	 * 
	 * @param standardCode
	 * @return
	 */
	public static boolean isDBStandardCode(String standardCode) {

		if (standardCode == null || standardCode.equals("")) {
			// log.info("subjectString is null:" + standardCode);
			return false;
		}

		// log.info("dbFullStandardReg : " + dbFullStandardReg);
		return standardCode.matches(dbFullStandardReg);
	}

	/**
	 * 用来判断是否是国家标准(GB) (按照GB/T 1.1-2000 要求)
	 * 
	 * @param standardCode
	 * @return
	 */
	public static boolean isGBStandardCode(String standardCode) {

		// 不包含空格或年号分隔符
		if (standardCode == null || standardCode.equals("")
				|| !StringUtils.contains(standardCode, blankSpace)
				|| !StringUtils.contains(standardCode, '-'))
			return false;

		// log.info("mainStandardCodeReg : " + standardCode);
		// log.info("mainGBStandardCodeReg : " + mainGBStandardCodeReg);
		return standardCode.matches(mainGBStandardCodeReg);
	}

	/**
	 * 用来判断是否是行业标准 (按照GB/T 1.1-2000 要求)，不判断该行业标准类别是否在平台中存在。
	 * 
	 * @param standardCode
	 *            待判断的标准号
	 * @return
	 */

	public static boolean isHBStandardCode(String standardCode) {

		// 不包含空格或年号分隔符
		if (standardCode == null || standardCode.equals("")
				|| standardCode.startsWith("GB")
				|| !StringUtils.contains(standardCode, blankSpace)
				|| !StringUtils.contains(standardCode, '-'))
			return false;

		// out.println(StringUtils.substringAfter(standardCode, blankSpace));
		// out.println(standardCodeYearReg);

		// String preMatche = StringUtils
		// .substringBefore(standardCode, blankSpace);
		// String afterMatche = StringUtils.substringAfter(standardCode,
		// blankSpace);

		return standardCode.matches(mainHBStandardCodeReg);

	}

	/**
	 * 判断中文名称不为空
	 * 
	 * @param namecnString
	 * @return
	 */
	public static boolean isNameCN(String namecnString) {

		return namecnString != null && !namecnString.equals("");

	}

	/**
	 * 判断英文名称。暂时不做判断。
	 * 
	 * @param nameenString
	 * @return
	 */
	public static boolean isNameEN(String nameenString) {

		return true;

	}

	/**
	 * 此函数用来判断是否是正确的年份,必须以 19,20,21 开头，并且是四位
	 * 
	 * @param year
	 * @return
	 */
	// public static boolean isRightYear(String year) {
	// // log.info("subjectString :" + subjectString);
	// // log.info(subjectString.matches(rightYearReg));
	// return year.matches(rightYearReg);
	// }

	/**
	 * 判断是否为正确的日期格式 xxxx-xx-xx
	 * 
	 * @param dateString
	 * @return
	 */
	public static boolean isDateFormat(String dateString) {

		if (dateString == null)
			return false;
		return dateString.matches(dateReg);

	}

	/**
	 * 检查是否为 CCS 格式。用正则表达式实现。多个 CCS 号码中间用分号隔开。
	 * 
	 * @param ccsString
	 * @return
	 */
	public static boolean isCCSCode(String ccsString) {

		if (ccsString == null || ccsString.equals(""))
			return true;

		StringTokenizer st = new StringTokenizer(ccsString, ";");
		while (st.hasMoreTokens()) {
			String temp = st.nextElement().toString();
			// out.println(temp);
			if (!temp.matches(CCS))
				return false;
		}

		return true;
	}

	/**
	 * 检查是否为 ICS 格式。用正则表达式实现。多个 ICS 号码中间用分号隔开。
	 * 
	 * @param icsString
	 * @return
	 */
	public static boolean isICSCode(String icsString) {

		if (icsString == null || icsString.equals(""))
			return true;

		StringTokenizer st = new StringTokenizer(icsString, ";");
		while (st.hasMoreTokens()) {
			String temp = st.nextElement().toString();
			// out.println(temp);
			if (!temp.matches(ICS))
				return false;
		}

		return true;
	}

	public static boolean isStatusCode(String StatusString) {

		if (StatusString == null || StatusString.equals(""))
			return true;

		return StatusString.equals("YX") || StatusString.equals("FZ");
	}

	/**
	 * 判断是否为语言代码。这里写死了，应该从数据库中读出，以后改写。
	 * 
	 * @param languageCode
	 * @return
	 */
	public static boolean isLanguageCode(String languageCode) {

		if (languageCode == null)
			return false;

		return languageCode.equals("CHINESE") || languageCode.equals("ENGLISH")
				|| languageCode.equals("FRENCH")
				|| languageCode.equals("GERMAN")
				|| languageCode.equals("JAPANESE")
				|| languageCode.equals("ENGLISH & FRENCH")
				|| languageCode.equals("ENGLISH & FRENCH & RUSSIAN");

	}

	/**
	 * 检查是否为 正整数 格式。用正则表达式实现
	 * 
	 * @param icsString
	 * @return
	 */

	public static boolean isPageNumber(String pageString) {

		if (pageString == null || pageString.equals(""))
			return true;

		return pageString.matches(number);

	}

	/**
	 * 判断 one 类别
	 * 
	 * @param classOneCodeString
	 * @return
	 */
	public static boolean isClassOneCode(String classOneCodeString) {

		return classOneCodeString == null || classOneCodeString.equals("")
				|| classOneCodeString.equals("GW")
				|| classOneCodeString.equals("GN");
	}

	/**
	 * 判断 two 类别
	 * 
	 * @param classTwoCodeString
	 * @return
	 */
	public static boolean isClassTwoCode(String classTwoCodeString) {

		return classTwoCodeString == null || classTwoCodeString.equals("")
				|| classTwoCodeString.equals("GB")
				|| classTwoCodeString.equals("HB")
				|| classTwoCodeString.equals("DB")
				|| classTwoCodeString.equals("QB");

	}

	/**
	 * 判断 three 类别，暂时不到平台中验证。
	 * 
	 * @param standardCode
	 *            标准号
	 * @param classThreeCodeString
	 *            标准类别代号
	 * @return
	 */
	public static boolean isClassThreeCode(String standardCode,
			String classThreeCodeString) {

		// log.info("standardCode : " + standardCode);
		// log.info("classThreeCodeString : " + classThreeCodeString);
		// log.info("getClassCodeFromStandardCode() : "
		// + getClassCodeFromStandardCode(standardCode));

		if (standardCode == null || standardCode.equals(""))
			return true;

		return classThreeCodeString == null
				|| classThreeCodeString.equals("")
				|| getClassCodeFromStandardCode(standardCode).equals(
						classThreeCodeString);

	}

	/**
	 * 判断 four 类别，是否为 T 推荐信、Q 强制性、Z 指导性。对于平台导入程序，会自动根据标准号生成，所以为空也可。
	 * 
	 * @param classFourCodeString
	 * @return
	 */
	public static boolean isClassFourCode(String standardCode,
			String classFourCodeString) {

		if (classFourCodeString == null || classFourCodeString.equals(""))
			return true;

		else if (getTypeFromStandardCode(standardCode) != null
				&& !getTypeFromStandardCode(standardCode).equals(
						classFourCodeString))
			return false;

		else
			return classFourCodeString.equals("T")
					|| classFourCodeString.equals("Q")
					|| classFourCodeString.equals("Z");

	}

	/**
	 * 判断是否代替标准号。代替标准号只能为一个标准号，暂时判断是否为国内标准
	 * 
	 * @param replaceStandardCodeString
	 * @return
	 */
	public static boolean isReplaceStandardCode(String replaceStandardCodeString) {

		if (replaceStandardCodeString == null
				|| replaceStandardCodeString.equals(""))
			return true;

		return isGBStandardCode(replaceStandardCodeString);

	}

	/**
	 * 判断是否被代替标准号。代替标准号是一系列标准，中间用分号隔开。部分代替情况不考虑
	 * 
	 * @param replacedStandardCodeString
	 * @return
	 */
	public static boolean isReplacedStandardCode(
			String replacedStandardCodeString) {

		if (replacedStandardCodeString == null
				|| replacedStandardCodeString.equals(""))
			return true;

		StringTokenizer st = new StringTokenizer(replacedStandardCodeString,
				";");
		while (st.hasMoreTokens()) {
			String temp = st.nextElement().toString();
			// out.println(temp);
			if (!isGNStandardCode(temp))
				return false;
		}
		return true;
	}

	// REPLACE_STANDARD
	//
	// REPLACED_STANDARD

	/**
	 * 检查是否为多个标准号的格式，标准号之间用指定的分隔符。
	 * 
	 * @param multiStandardCode
	 * @param separatorChar
	 *            分隔符字符数组，包含任何一个均可。
	 * @return
	 */
	public static boolean isMultiStandardCodeFormat(String multiStandardCode,
			char separatorChar[]) {
		return true;
	}

	/**
	 * 用来判断特殊类型标准
	 * 
	 * @param standardCode
	 * @return
	 */
	public static boolean isSpecailStandardCode(String standardCode) {

		// 如果添加了特殊类别，均要重新检查几个 getXXX 函数

		// 判断 QJ ,GJB 类型标准
		if (standardCode.startsWith("QJ") || standardCode.startsWith("GJB"))
			return standardCode.matches(mainQJGJBStandardCodeReg);

		// NY 判断农业标准
		if (standardCode.startsWith("NY"))
			return standardCode.matches(mainNYStandardCodeReg);
		return false;

	}

	/**
	 * 此函数用来判断给定的集合中是否有重复的标准,主要用来检查同一个标准号，强标、推标、指导性技术文件同时存在的现象。如果待确定的集合过大，
	 * 比较次数会很多，有效率问题 。
	 * 
	 * @param StandardCodeList
	 *            待检查的包含标准号的集合
	 * @param validate
	 *            是否进行标准号规范化验证
	 * @param classCode
	 *            进行标准号标准化验证时，用到的标准平台中的标准类别集合
	 */
	public void isReduplicateStandardCode(List<String> StandardCodeList,
			boolean validate, List<String> classCode) {

		// === 得到几个结果集，可以进一步处理，例如输出到文件

		// 存放不规范的标准号
		ArrayList<String> wrongList = new ArrayList<String>();

		// 存放检查出来重复的标准号，用 LinkedHashSet 的目的 是过滤重复元素，且集合里面的元素按照插入的时候的顺序进行排序
		LinkedHashSet<String> reduplicateSet = new LinkedHashSet<String>();

		// 存放不重复的、正确的标准号
		ArrayList<String> resultList = new ArrayList<String>();

		int size = StandardCodeList.size();

		// 集合相互比较，不满足条件的原始设置为 null，注意循环条件，要防止访问 null
		for (int i = 0; i < size; i++) {// 外循环
			String stri = StandardCodeList.get(i);
			if (stri == null)
				continue;

			if (validate && !isGNStandardCode(stri)) {
				wrongList.add(stri);
				StandardCodeList.set(i, null);
				continue;
			}

			for (int j = i + 1; j < size; j++) {// 内循环
				String strj = StandardCodeList.get(j);
				if (strj == null)
					continue;

				if (validate && !isGNStandardCode(strj)) {
					wrongList.add(strj);
					StandardCodeList.set(j, null);
					continue;
				}

				// log.info(stri);
				String striTemp = stri;
				striTemp = StringUtils.remove(striTemp, "/T");
				striTemp = StringUtils.remove(striTemp, "/Z");
				striTemp = StringUtils.remove(striTemp, "/");

				// log.info(" striTemp ==== " + striTemp);

				// log.info(strj);
				String strjTemp = strj;
				strjTemp = StringUtils.remove(strjTemp, "/T");
				strjTemp = StringUtils.remove(strjTemp, "/Z");
				strjTemp = StringUtils.remove(strjTemp, "/");

				// log.info(" strjTemp ==== " + strjTemp);

				if (striTemp.equals(strjTemp)) {
					if (!reduplicateSet.contains(stri))
						reduplicateSet.add(stri);
					reduplicateSet.add(strj);
					StandardCodeList.set(i, null);
					StandardCodeList.set(j, null);
				}

			}// 内循环结束
		}// 外循环结束

		// 组装不重复的标准号数据
		for (String s : StandardCodeList)
			if (s != null)
				resultList.add(s);

		// 测试信息
		System.out.println("重复的标准号");
		for (String s : reduplicateSet)
			System.out.println(s);

		// 把重复的标准号写入文件
		try {
			FileUtils.writeLines(new File(
					"D:\\ftpFiles\\StandardCodeOnly_20100106_re.txt"),
					reduplicateSet);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return;

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		// List<String> classCode = StandardClassUtils.getInstance()
		// .getGNClassCode();

		// ArrayList<String> al = new ArrayList<String>();
		// al.add("DB11/ 123-2003");
		// al.add("DB11/T 123-2003");
		// al.add("DB11/Z 123-2003");
		// al.add("DB11 123-2003");
		// al.add("JB 123-2003");
		// al.add("JB/T 123-200");
		// al.add("JB/Z 123-2003");
		// al.add("LY/ 123-2003");

		// String replaced_standardcode =
		// "GB/T 123-2003;GB 123-2009;DB11/Z 123-2003;DB11/T 123-2003;DB11/ 123-2003;JB 123-2003";

		// out.println(StandardUtils.isReplacedStandardCode(replaced_standardcode));

		// out.println(StandardUtils.isDBStandardCode("DB31/T 511-2010"));
		// out.println(StandardUtils.isHBStandardCode("SY/T 5592-1993"));
		// out.println(StandardUtils.isGBStandardCode("GB/T 1.1-2000"));
		// out.println(StandardUtils.isGBStandardCode("GB 3497-l983"));

		out.println(StandardUtils.getReverseTypeStandardCode("DB11/T 3497-1983"));
		// StandardUtils

		// QJ 1145.2A-2007
		// System.out.println(StandardCodeUtils.isGBorHBcode("CJ/T 273-2008",
		// St_Class.getClassCode_GN()));

		// for (String test : isReduplicateStandardCode(al))
		// System.out.println(test);

		// 地标测试
		// System.out.println(getKindFromStandardCode("DB1/Z 123-2003"));

		// System.out.println(isDBcode("DB11 123-2003"));

		// 国标测试
		// System.out.println(isGBcode("GB/T 123-2003"));
		// System.out.println(isGBcode("GB/Z 123.23-2003"));
		// System.out.println(isGBcode("GB 123-2003"));
		// System.out.println(isGBcode("GB/F 123-2003"));

		// 行标测试
		// System.out.println(isHBcode("JB/Z 123-2003", classCode));
		// System.out.println(isHBcode("DL/T 123.23-2003", classCode));
		// System.out.println(isHBcode("DL/T 123-2003", classCode));
		// System.out.println(isHBcode("LL/T 123-2003", classCode));
		// System.out.println(isHBcode("DL123-2003", classCode));
		// System.out.println(isHBcode("FJ/Z 123.2A-1989", classCode));
		// System.out.println(isHBcode("GJB 123B-198", classCode));
		// System.out.println(isHBcode("NY 123.23-1989", classCode));
		// System.out.println(isHBcode("NY/T 123.23.321-1989", classCode));

		// 测试标准号规范函数
		// GB13693-2005
		// GBZ 2-2002
		// GB T 9634.4-2007
		// GB/T16720.1-2005
		// GB 9634.4-97
		// GB/T 8321.1-2000
		// GB/T11828.2
		// GB/T A13843-1992
		// GB/Y 10001.4-2003
		// DZ 0004-91

		// System.out.println(getStandardCode("db1/123.23-89", classCode));
		// System.out.println(getStandardCode("db11/123.23-89", classCode));
		// System.out.println(getStandardCode("db11T123.23-89", classCode));
		// System.out.println(getStandardCode("db11/Z123.23-89", classCode));
		// System.out.println(getStandardCode("DLT 123.23-89", classCode));
		// System.out.println(getStandardCode("DLT123.23-89", classCode));
		// System.out.println(getStandardCode("GB13693-2005", classCode));
		// System.out.println(getStandardCode("GB T 9634.4-2007", classCode));
		// System.out.println(getStandardCode("GB/T16720.1-2005", classCode));
		// System.out.println(getStandardCode("GB/T11828.2", classCode));
		// System.out.println(getStandardCode("DZ 0004-91", classCode));
		// System.out.println(getStandardCode("GBZ 2-2002", classCode));

		// isReduplicateStandardCode(al, false, classCode);

	}

}